/**************************************************************************************************
* Title: SumVector2.inl
* Author: Gael Huber
* Description: Implementation of Vector2 struct and related functions
**************************************************************************************************/

/**************************************************************************************************
* Default constructor
**************************************************************************************************/
inline Vector2::Vector2(void) 
	: x(0.0f), y(0.0f)
{ }

/**************************************************************************************************
* Constructor from array
**************************************************************************************************/
inline Vector2::Vector2(const float* f) 
	: x(f[0]), y(f[1])
{ }

/**************************************************************************************************
* Constructor specifying values
**************************************************************************************************/
inline Vector2::Vector2(float x, float y) 
	: x(x), y(y)
{ }

/**************************************************************************************************
* Copy constructor
**************************************************************************************************/
inline Vector2::Vector2(const Vector2& rhs) 
	: x(rhs.x), y(rhs.y)
{ }

/**************************************************************************************************
* Destructor
**************************************************************************************************/
inline Vector2::~Vector2(void) 
{}


/**************************************************************************************************
* Cast to non-const
**************************************************************************************************/
inline Vector2::operator float*(void) {
	return (float*) this;
}

/**************************************************************************************************
* Cast to const
**************************************************************************************************/
inline Vector2::operator const float*(void) const {
	return (const float*) this;
}

/**************************************************************************************************
* Assignment operator
**************************************************************************************************/
inline Vector2& Vector2::operator=(const Vector2& rhs) {
	// Self-assigment guard
	if(this == &rhs) {
		return *this;
	}

	// Copy and return
	x = rhs.x;
	y = rhs.y;

	return *this;
}

/**************************************************************************************************
* Addition assignment operator
**************************************************************************************************/
inline Vector2& Vector2::operator+=(const Vector2& rhs) {
	x += rhs.x;
	y += rhs.y;
	return *this;
}

/**************************************************************************************************
* Subtraction assignment operator
**************************************************************************************************/
inline Vector2& Vector2::operator-=(const Vector2& rhs) {
	x -= rhs.x;
	y -= rhs.y;
	return *this;
}

/**************************************************************************************************
* Multiplication assignment operator
**************************************************************************************************/
inline Vector2& Vector2::operator*=(float rhs) {
	x *= rhs;
	y *= rhs;
	return *this;
}

/**************************************************************************************************
* Division assignment operator
**************************************************************************************************/
inline Vector2& Vector2::operator/=(float rhs) {
	const float f = 1.0f / rhs;
	x *= f;
	y *= f;
	return *this;
}

/**************************************************************************************************
* Return a positive version of the vector
**************************************************************************************************/
inline Vector2 Vector2::operator+(void) const {
	return *this;
}

/**************************************************************************************************
* Return a negated version of the vector
**************************************************************************************************/
inline Vector2 Vector2::operator-(void) const {
	return Vector2(-x, -y);
}

/**************************************************************************************************
* Sum of two vectors
**************************************************************************************************/
inline Vector2 Vector2::operator+(const Vector2& rhs) const {
	return Vector2(x + rhs.x, y + rhs.y);
}

/**************************************************************************************************
* Difference between two vectors
**************************************************************************************************/
inline Vector2 Vector2::operator-(const Vector2& rhs) const {
	return Vector2(x - rhs.x, y - rhs.y);
}

/**************************************************************************************************
* Multiply by a value
**************************************************************************************************/
inline Vector2 Vector2::operator*(float rhs) const {
	return Vector2(x * rhs, y * rhs);
}

/**************************************************************************************************
* Divide by a value
**************************************************************************************************/
inline Vector2 Vector2::operator/(float rhs) const {
	const float f = 1.0f / rhs;
	return Vector2(x * f, y * f);
}
	
/**************************************************************************************************
* Multiply by a value
**************************************************************************************************/
inline Vector2 operator*(float lhs, const Vector2& rhs) {
	return Vector2(lhs * rhs.x, lhs * rhs.y);
}

/**************************************************************************************************
* Equivalence
**************************************************************************************************/
inline bool Vector2::operator==(const Vector2& rhs) const {
	return (x == rhs.x && y == rhs.y);
}

/**************************************************************************************************
* Non-equivalence
**************************************************************************************************/
inline bool Vector2::operator!=(const Vector2& rhs) const {
	return (x != rhs.x || y != rhs.y);
}

/**************************************************************************************************
* Length
**************************************************************************************************/
inline float Vec2Length(const Vector2* pV) {
	return sqrtf(pV->x*pV->x + pV->y*pV->y);
}

/**************************************************************************************************
* Squared length
**************************************************************************************************/
inline float Vec2LengthSqr(const Vector2* pV) {
	return pV->x*pV->x + pV->y*pV->y;
}

/**************************************************************************************************
* Dot product
**************************************************************************************************/
inline float Vec2Dot(const Vector2* pV1, const Vector2* pV2) {
	return pV1->x*pV2->x + pV1->y*pV2->y;
}

/**************************************************************************************************
* Z component of cross product
**************************************************************************************************/
inline float Vec2CCW(const Vector2* pV1, const Vector2* pV2) {
	return pV1->x*pV2->y - pV1->y*pV2->x;
}

/**************************************************************************************************
* Addition
**************************************************************************************************/
inline Vector2* Vec2Add(Vector2* pOut, const Vector2* pV1, const Vector2* pV2) {
	pOut->x = pV1->x + pV2->x;
	pOut->y = pV1->y + pV2->y;
	return pOut;
}

/**************************************************************************************************
* Subtraction
**************************************************************************************************/
inline Vector2* Vec2Sub(Vector2* pOut, const Vector2* pV1, const Vector2* pV2) {
	pOut->x = pV1->x - pV2->x;
	pOut->y = pV1->y - pV2->y;
	return pOut;
}

/**************************************************************************************************
* Minimize each component
**************************************************************************************************/
inline Vector2* Vec2Minimize(Vector2* pOut, const Vector2* pV1, const Vector2* pV2) {
	pOut->x = pV1->x > pV2->x ? pV2->x : pV1->x;
	pOut->y = pV1->y > pV2->y ? pV2->y : pV1->y;
	return pOut;
}

/**************************************************************************************************
* Maximize each component
**************************************************************************************************/
inline Vector2* Vec2Maximize(Vector2* pOut, const Vector2* pV1, const Vector2* pV2) {
	pOut->x = pV1->x > pV2->x ? pV1->x : pV2->x;
	pOut->y = pV1->y > pV2->y ? pV1->y : pV2->y;
	return pOut;
}

/**************************************************************************************************
* Scale the vector
**************************************************************************************************/
inline Vector2* Vec2Scale(Vector2* pOut, const Vector2* pV, float s) {
	pOut->x = pV->x * s;
	pOut->y = pV->y * s;
	return pOut;
}

/**************************************************************************************************
* Linear interpolation V1 + s(V2 - V1)
**************************************************************************************************/
inline Vector2* Vec2Lerp(Vector2* pOut, const Vector2* pV1, const Vector2* pV2, float s) {
	*pOut = *pV1 + s * (*pV2 - *pV1);
	return pOut;
}

/**************************************************************************************************
* Normalize
**************************************************************************************************/
inline Vector2* Vec2Normalize(Vector2* pOut, const Vector2* pV) {
	*pOut = *pV / Vec2Length(pV);
	return pOut;
}